import numpy as np
from initialization import initialization
def ETO(N, Max_Iter, LB, UB, Dim, Fobj):
    Destination_position = np.zeros(Dim)
    Destination_fitness = np.inf
    Destination_position_second = np.zeros(Dim)
    Convergence_curve = np.zeros(Max_Iter)
    Position_sort = np.zeros((N, Dim))

    # 初始化ETO参数
    b = 1.55
    CE = int(np.floor(1 + (Max_Iter / b)))
    T = int(np.floor(1.2 + Max_Iter / 2.25))
    CEi = 0
    CEi_temp = 0
    UB_2 = np.array(UB)
    LB_2 = np.array(LB)

   #初始化随机方案集
    X = initialization(N, Dim, UB, LB)
    Objective_values = np.zeros(N)

    # 计算适应度并找到最好的
    for i in range(N):
        Objective_values[i] = Fobj(X[i, :])
        if Objective_values[i] < Destination_fitness:
            Destination_position = X[i, :].copy()
            Destination_fitness = Objective_values[i]

    Convergence_curve[0] = Destination_fitness
    t = 1

    # 主循环
    while t < Max_Iter:
        for i in range(N):
            for j in range(Dim):
                d1 = 0.1 * np.exp(-0.01 * t) * np.cos(0.5 * Max_Iter * (1 - t / Max_Iter))
                d2 = -0.1 * np.exp(-0.01 * t) * np.cos(0.5 * Max_Iter * (1 - t / Max_Iter))
                CM = (np.sqrt(t / Max_Iter) ** np.tan(d1 / d2)) * np.random.rand() * 0.01

                if t == CEi:
                    UB_2[j] = Destination_position[j] + (1 - t / Max_Iter) * abs(
                        np.random.rand() * Destination_position[j] - Destination_position_second[j]) * np.random.rand()
                    LB_2[j] = Destination_position[j] - (1 - t / Max_Iter) * abs(
                        np.random.rand() * Destination_position[j] - Destination_position_second[j]) * np.random.rand()
                    UB_2[j] = min(UB_2[j], UB[j])
                    LB_2[j] = max(LB_2[j], LB[j])
                    X = initialization(N, Dim, UB_2, LB_2)
                    CEi_temp = CEi
                    CEi = 0

                if t <= T:
                    q1 = np.random.rand()
                    q3 = np.random.rand()
                    q4 = np.random.rand()

                    if CM > 1:
                        d1 = 0.1 * np.exp(-0.01 * t) * np.cos(0.5 * Max_Iter * q1)
                        d2 = -0.1 * np.exp(-0.01 * t) * np.cos(0.5 * Max_Iter * q1)
                        alpha_1 = np.random.rand() * 3 * (t / Max_Iter - 0.85) * np.exp(abs(d1 / d2) - 1)
                        if q1 <= 0.5:
                            X[i, j] = Destination_position[j] + np.random.rand() * alpha_1 * abs(Destination_position[j] - X[i, j])
                        else:
                            X[i, j] = Destination_position[j] - np.random.rand() * alpha_1 * abs(Destination_position[j] - X[i, j])
                    else:
                        d1 = 0.1 * np.exp(-0.01 * t) * np.cos(0.5 * Max_Iter * q3)
                        d2 = -0.1 * np.exp(-0.01 * t) * np.cos(0.5 * Max_Iter * q3)
                        alpha_3 = np.random.rand() * 3 * (t / Max_Iter - 0.85) * np.exp(abs(d1 / d2) - 1.3)
                        if q3 <= 0.5:
                            X[i, j] = Destination_position[j] + q4 * alpha_3 * abs(np.random.rand() * Destination_position[j] - X[i, j])
                        else:
                            X[i, j] = Destination_position[j] - q4 * alpha_3 * abs(np.random.rand() * Destination_position[j] - X[i, j])
                else:
                    q2 = np.random.rand()
                    alpha_2 = np.random.rand() * np.exp(np.tanh(1.5 * (-t / Max_Iter - 0.75) - np.random.rand()))
                    if CM < 1:
                        d1 = 0.1 * np.exp(-0.01 * t) * np.cos(0.5 * Max_Iter * q2)
                        d2 = -0.1 * np.exp(-0.01 * t) * np.cos(0.5 * Max_Iter * q2)
                        #加入限制
                        epsilon = 1e-8
                        safe_ratio = d1 / (d2 + epsilon)
                        safe_tan = np.tan(np.clip(np.abs(safe_ratio), -np.pi / 2 + 0.01, np.pi / 2 - 0.01))
                        exp_input = safe_tan * abs(np.random.rand() * alpha_2 * Destination_position[j] - X[i, j])
                        X[i, j] = X[i, j] + np.exp(np.clip(exp_input, -100, 100))  # 限制指数输入，避免爆炸


                    else:
                        if q2 <= 0.5:
                            X[i, j] = X[i, j] + 3 * abs(np.random.rand() * alpha_2 * Destination_position[j] - X[i, j])
                        else:
                            X[i, j] = X[i, j] - 3 * abs(np.random.rand() * alpha_2 * Destination_position[j] - X[i, j])

            CEi = CEi_temp

        for i in range(N):
            Flag4ub = X[i, :] > UB_2
            Flag4lb = X[i, :] < LB_2
            #避免无效值
            X[i, :] = np.nan_to_num(X[i, :])  # 把 NaN 变成 0，inf 变成一个大数
            X[i, :] = (X[i, :] * (~(Flag4ub + Flag4lb))) + ((UB_2 + LB_2) / 2) * Flag4ub + LB_2 * Flag4lb


            Objective_values[i] = Fobj(X[i, :])
            if Objective_values[i] < Destination_fitness:
                Destination_position = X[i, :].copy()
                Destination_fitness = Objective_values[i]

        if t == CE:
            CEi = CE + 1
            CE = CE + int(np.floor(2 - t * 2 / (Max_Iter - CE * 4.6)))
            Position_sort = X.copy()
            sort_idx = np.argsort(Objective_values)
            Position_sort = Position_sort[sort_idx]
            Objective_values = Objective_values[sort_idx]
            Destination_position_second = Position_sort[1, :].copy()

        Convergence_curve[t] = Destination_fitness
        t += 1

    return Destination_fitness, Destination_position, Convergence_curve
